﻿#include "MagicInfo.h"
#include "../../Shared/ServerPackets.h"

using namespace Server::MirEnvir;
namespace S = ServerPackets;

namespace Server::MirDatabase
{

    Server::MirEnvir::Envir *MagicInfo::getEnvir()
    {
        return Envir::getMain();
    }

    std::string MagicInfo::ToString()
    {
        return Name;
    }

    MagicInfo::MagicInfo()
    {

    }

    MagicInfo::MagicInfo(BinaryReader *reader, int version, int Customversion)
    {
        Name = reader->ReadString();
        Spell = static_cast<Spell>(reader->ReadByte());
        BaseCost = reader->ReadByte();
        LevelCost = reader->ReadByte();
        Icon = reader->ReadByte();
        Level1 = reader->ReadByte();
        Level2 = reader->ReadByte();
        Level3 = reader->ReadByte();
        Need1 = reader->ReadUInt16();
        Need2 = reader->ReadUInt16();
        Need3 = reader->ReadUInt16();
        DelayBase = reader->ReadUInt32();
        DelayReduction = reader->ReadUInt32();
        PowerBase = reader->ReadUInt16();
        PowerBonus = reader->ReadUInt16();
        MPowerBase = reader->ReadUInt16();
        MPowerBonus = reader->ReadUInt16();

        if (version > 66)
        {
            Range = reader->ReadByte();
        }
        if (version > 70)
        {
            MultiplierBase = reader->ReadSingle();
            MultiplierBonus = reader->ReadSingle();
        }
    }

    void MagicInfo::Save(BinaryWriter *writer)
    {
        writer->Write(Name);
        writer->Write(static_cast<unsigned char>(Spell));
        writer->Write(BaseCost);
        writer->Write(LevelCost);
        writer->Write(Icon);
        writer->Write(Level1);
        writer->Write(Level2);
        writer->Write(Level3);
        writer->Write(Need1);
        writer->Write(Need2);
        writer->Write(Need3);
        writer->Write(DelayBase);
        writer->Write(DelayReduction);
        writer->Write(PowerBase);
        writer->Write(PowerBonus);
        writer->Write(MPowerBase);
        writer->Write(MPowerBonus);
        writer->Write(Range);
        writer->Write(MultiplierBase);
        writer->Write(MultiplierBonus);
    }

    Server::MirEnvir::Envir *UserMagic::getEnvir()
    {
        return Envir::getMain();
    }

    MagicInfo *UserMagic::GetMagicInfo(Spell spell)
    {
        for (int i = 0; i < getEnvir()->MagicInfoList.size(); i++)
        {
            MagicInfo *info = getEnvir()->MagicInfoList[i];
            if (info->Spell != spell)
            {
                continue;
            }
            return info;
        }
        return nullptr;
    }

    UserMagic::UserMagic(Spell spell)
    {
        Spell = spell;

        Info = GetMagicInfo(Spell);
    }

    UserMagic::UserMagic(BinaryReader *reader)
    {
        Spell = static_cast<Spell>(reader->ReadByte());
        Info = GetMagicInfo(Spell);

        Level = reader->ReadByte();
        Key = reader->ReadByte();
        Experience = reader->ReadUInt16();

        if (Envir::LoadVersion < 15)
        {
            return;
        }
        IsTempSpell = reader->ReadBoolean();

        if (Envir::LoadVersion < 65)
        {
            return;
        }
        CastTime = reader->ReadInt64();
    }

    void UserMagic::Save(BinaryWriter *writer)
    {
        writer->Write(static_cast<unsigned char>(Spell));

        writer->Write(Level);
        writer->Write(Key);
        writer->Write(Experience);
        writer->Write(IsTempSpell);
        writer->Write(CastTime);
    }

    Packet *UserMagic::GetInfo()
    {
        S::NewMagic *tempVar = new S::NewMagic();
        tempVar->Magic = CreateClientMagic();

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was used in a 'return' or 'throw' statement.
        return tempVar;
    }

    ClientMagic *UserMagic::CreateClientMagic()
    {
        ClientMagic *tempVar = new ClientMagic();
        tempVar->Name = Info->Name;
        tempVar->Spell = Spell;
        tempVar->BaseCost = Info->BaseCost;
        tempVar->LevelCost = Info->LevelCost;
        tempVar->Icon = Info->Icon;
        tempVar->Level1 = Info->Level1;
        tempVar->Level2 = Info->Level2;
        tempVar->Level3 = Info->Level3;
        tempVar->Need1 = Info->Need1;
        tempVar->Need2 = Info->Need2;
        tempVar->Need3 = Info->Need3;
        tempVar->Level = Level;
        tempVar->Key = Key;
        tempVar->Experience = Experience;
        tempVar->IsTempSpell = IsTempSpell;
        tempVar->Delay = GetDelay();
        tempVar->Range = Info->Range;
        tempVar->CastTime = (CastTime != 0) && (getEnvir()->getTime() > CastTime)? getEnvir()->getTime() - CastTime: 0;

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was used in a 'return' or 'throw' statement.
        return tempVar;
    }

    int UserMagic::GetDamage(int DamageBase)
    {
        return static_cast<int>((DamageBase + GetPower()) * GetMultiplier());
    }

    float UserMagic::GetMultiplier()
    {
        return (Info->MultiplierBase + (Level * Info->MultiplierBonus));
    }

    int UserMagic::GetPower()
    {
        return static_cast<int>(BankersRounding::round((MPower() / 4.0F) * (Level + 1) + DefPower()));
    }

    int UserMagic::MPower()
    {
        if (Info->MPowerBonus > 0)
        {
            return getEnvir()->Random->Next(Info->MPowerBase, Info->MPowerBonus + Info->MPowerBase);
        }
        else
        {
            return Info->MPowerBase;
        }
    }

    int UserMagic::DefPower()
    {
        if (Info->PowerBonus > 0)
        {
            return getEnvir()->Random->Next(Info->PowerBase, Info->PowerBonus + Info->PowerBase);
        }
        else
        {
            return Info->PowerBase;
        }
    }

    int UserMagic::GetPower(int power)
    {
        return static_cast<int>(BankersRounding::round(power / 4.0F * (Level + 1) + DefPower()));
    }

    long long UserMagic::GetDelay()
    {
        return Info->DelayBase - (Level * Info->DelayReduction);
    }
}
